package com.mxpio.erp.equipment.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.mxpio.erp.common.enums.EquipmentEnums;
import com.mxpio.erp.common.equipment.entity.*;
import com.mxpio.erp.common.equipment.service.*;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.lin.Linq;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.security.entity.Dept;
import com.mxpioframework.security.entity.User;
import com.mxpioframework.security.entity.UserDept;
import com.mxpioframework.security.util.SecurityUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 保养任务Service业务层处理
 *
 * @author Cheng
 * @date 2023-07-28
 */
@Service
public class EquipmentUpkeepTaskServiceImpl extends BaseServiceImpl<EquipmentUpkeepTask> implements EquipmentUpkeepTaskService {

    public static final String DEPART_RELEASE_TARGET = "department";
    public static final String PERSON_GROUP_RELEASE_TARGET = "person_group";
    public static final String PERSONAL_RELEASE_TARGET = "personal";
    public static final String ASSIGN_MODE = "assign";
    public static final String GRAB_MODE = "grab";

    @Resource
    private EquipmentAreaService equipmentAreaService;
    @Resource
    private EquipmentPersonGroupService personGroupService;
    @Resource
    private EquipmentUpkeepTaskDetailService upkeepTaskDetailService;
    @Resource
    private EquipmentUpkeepTaskOperationService upkeepTaskOperationService;
    @Resource
    private EquipmentUpkeepTaskTransferService upkeepTaskTransferService;

    @Override
    @Transactional(readOnly = true)
    public Page<EquipmentUpkeepTask> taskPage(String flag, Pageable page, Criteria criteria) {
        Linq linq = JpaUtil.linq(EquipmentUpkeepTask.class).where(criteria);
        String username = SecurityUtils.getLoginUsername();
        if("task".equals(flag)){
            linq = linq.or()
                    .equal("director", username)
                    .equal("executor", username)
                    .equal("dispatchUser", username)
                    .equal("createBy", username)
                    .end();
        }else if ("release".equals(flag)) {
            linq = linq
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.START.getCode())
                    .or()
                    .equal("director", username)
                    .equal("executor", username)
                    .equal("dispatchUser", username)
                    .equal("createBy", username)
                    .end();
        }else if ("send".equals(flag)) {
            linq = linq
                    //派工模式为派工
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.RELEASE.getCode())
                    .equal("dispatchMode", ASSIGN_MODE)
                    .equal("director", username);
        }else if (GRAB_MODE.equals(flag)) {
            List<Dept> depts = queryUserDeparts(username);
            List<String> departs = depts.stream().map(a -> a.getId()).collect(Collectors.toList());
            List<String> groups = personGroupService.selectByUsername(username);
            groups.addAll(departs);
            linq = linq
                    //派工模式为抢单
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.RELEASE.getCode())
                    .equal("dispatchMode", GRAB_MODE)
                    .in("releaseTargetId", groups);
        }else if ("execute".equals(flag)) {
            linq = linq
                    .equal("executor", username)
                    .or()
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode())
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.EXECUT.getCode())
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.STOP.getCode())
                    .end();
        }else if ("toExecute".equals(flag)) {
            linq = linq
                    .equal("executor", username)
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());
        }else if ("executing".equals(flag)) {
            linq = linq
                    .equal("executor", username)
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.EXECUT.getCode());
        }else if ("stop".equals(flag)) {
            linq = linq
                    .equal("executor", username)
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.STOP.getCode());
        }else if ("record".equals(flag)) {
            linq = linq
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.END.getCode())
                    .or()
                    .equal("director", username)
                    .equal("executor", username)
                    .equal("dispatchUser", username)
                    .equal("createBy", username)
                    .end();
        }else if ("executeOverdue".equals(flag)) {//逾期未执行
            //当前时间大于预计完成时间的未完工工单
            linq = linq
                    .equal("executor", username)
                    .or()
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode())
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.EXECUT.getCode())
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.STOP.getCode())
                    .end()
                    .gt("planEndTime", DateUtil.now());
        } else if ("overdueFinish".equals(flag)) {//逾期完成
            linq = linq
                    .equal("orderStatus", EquipmentEnums.UpkeepStatus.STOP.getCode())
                    .or()
                    .equal("director", username)
                    .equal("executor", username)
                    .equal("dispatchUser", username)
                    .equal("createBy", username)
                    .end()
                    .lt("planEndTime","actualEndTime");
        }

        return linq.paging(page);
    }

    @Override
    @Transactional(readOnly = true)
    public List<EquipmentUpkeepTask> queryExecutingList() {
        return JpaUtil.linq(EquipmentUpkeepTask.class).in("orderStatus", 30, 40, 45).list();
    }

    @Override
    @Transactional
    public void saveTask(EquipmentUpkeepTask upkeepTask) {
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.START.getCode());

        /*if (EquipmentEnums.UpkeepPlanTarget.AREA_TARGET.getCode().equals(upkeepTask.getTargetType())) {
            // 查询区域信息
            EquipmentArea area = JpaUtil.getOne(EquipmentArea.class,upkeepTask.getTargetId());
            if (area == null) {
                return;
            }
            upkeepTask.setTargetCode(area.getAreaCode());
            if (area.getPid() != null && !"0".equals(area.getPid())) {
                String parentAllName = equipmentAreaService.getParentAllNameByPid(area.getPid());
                upkeepTask.setTargetName(parentAllName + area.getAreaName());
            } else {
                upkeepTask.setTargetName(area.getAreaName());
            }
        }*/
        // 获取部门或群组的负责人
        if (DEPART_RELEASE_TARGET.equals(upkeepTask.getReleaseTargetType())) {
            String departmentDirector = getDepartmentDirector(upkeepTask.getReleaseTargetId(), upkeepTask.getDispatchMode());
            upkeepTask.setDirector(departmentDirector);
        } else if (PERSON_GROUP_RELEASE_TARGET.equals(upkeepTask.getReleaseTargetType())) {
            // 获取群组主管
            EquipmentPersonGroup tpmPersonGroup = JpaUtil.getOne(EquipmentPersonGroup.class,upkeepTask.getReleaseTargetId());
            if (StringUtils.isEmpty(tpmPersonGroup.getDirectorId()) && ASSIGN_MODE.equals(upkeepTask.getDispatchMode())) {
                throw new MBootException("派工模式下该下达目标无负责人");
            }
            upkeepTask.setDirector(tpmPersonGroup.getDirectorId());
        }
        save(upkeepTask);
    }

    @Override
    @Transactional
    public void updateTask(EquipmentUpkeepTask upkeepTask) {
        if (EquipmentEnums.UpkeepPlanTarget.AREA_TARGET.getCode().equals(upkeepTask.getTargetType())) {
            // 查询区域信息
            EquipmentArea area = JpaUtil.getOne(EquipmentArea.class,upkeepTask.getTargetId());
            if (area == null) {
                return;
            }
            upkeepTask.setTargetCode(area.getAreaCode());
            if (area.getPid() != null && !"0".equals(area.getPid())) {
                String parentAllName = equipmentAreaService.getParentAllNameByPid(area.getPid());
                upkeepTask.setTargetName(parentAllName +"/"+ area.getAreaName());
            } else {
                upkeepTask.setTargetName(area.getAreaName());
            }
        }
        // 获取部门或群组的负责人
        if (DEPART_RELEASE_TARGET.equals(upkeepTask.getReleaseTargetType())) {
            String departmentDirector = getDepartmentDirector(upkeepTask.getReleaseTargetId(), upkeepTask.getDispatchMode());
            upkeepTask.setDirector(departmentDirector);
        } else if (PERSON_GROUP_RELEASE_TARGET.equals(upkeepTask.getReleaseTargetType())) {
            // 获取群组主管
            EquipmentPersonGroup tpmPersonGroup = JpaUtil.getOne(EquipmentPersonGroup.class,upkeepTask.getReleaseTargetId());
            if (StringUtils.isEmpty(tpmPersonGroup.getDirectorId()) && ASSIGN_MODE.equals(upkeepTask.getDispatchMode())) {
                throw new MBootException("派工模式下该下达目标无负责人");
            }
            upkeepTask.setDirector(tpmPersonGroup.getDirectorId());
        }
        this.update(upkeepTask);
    }

    @Override
    @Transactional
    public void release(String id) {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class,id);
        if (upkeepTask == null) {
            return;
        }
        if (!EquipmentEnums.UpkeepStatus.START.getCode().equals(upkeepTask.getOrderStatus())) {
            return;
        }
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.RELEASE.getCode());
        upkeepTask.setReleaseTime(new Date());

        if (PERSONAL_RELEASE_TARGET.equals(upkeepTask.getReleaseTargetType())) {
            // 如果是下达目标是个人，则直接跳过派工状态
            upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());
            upkeepTask.setDispatchTime(new Date());
            upkeepTask.setExecutor(upkeepTask.getReleaseTargetId());
        }
        this.update(upkeepTask);
    }

    @Override
    @Transactional
    public void dispatch(String id, String executor) throws MBootException {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class,id);
        if (upkeepTask == null) {
            return;
        }
        // 判断工单状态
        if (!EquipmentEnums.UpkeepStatus.RELEASE.getCode().equals(upkeepTask.getOrderStatus())) {
            return;
        }
        // 判断派工模式
        if (GRAB_MODE.equals(upkeepTask.getDispatchMode())) {
            throw new MBootException("非派工模式");
        }
        String loginUsername = SecurityUtils.getLoginUsername();
        upkeepTask.setExecutor(executor);
        upkeepTask.setDispatchTime(new Date());
        upkeepTask.setDispatchUser(loginUsername);
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());

        this.update(upkeepTask);
    }

    @Override
    @Transactional
    public void grab(String id) throws MBootException {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class,id);
        if (upkeepTask == null) {
            throw new MBootException("工单不存在");
        }
        // 判断工单状态
        if (!EquipmentEnums.UpkeepStatus.RELEASE.getCode().equals(upkeepTask.getOrderStatus())) {
            throw new MBootException("工单状态不正确");
        }
        // 判断派工模式
        if (ASSIGN_MODE.equals(upkeepTask.getDispatchMode())) {
            throw new MBootException("非抢单模式");
        }
        String loginUsername = SecurityUtils.getLoginUsername();
        upkeepTask.setExecutor(loginUsername);
        upkeepTask.setDispatchTime(new Date());
        upkeepTask.setDispatchUser(loginUsername);
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());

        this.update(upkeepTask);
    }

    @Override
    @Transactional
    public void excut(EquipmentUpkeepTask equipmentUpkeepTask) throws MBootException {
        EquipmentUpkeepTask tpmUpkeepTaskEntity = this.getById(EquipmentUpkeepTask.class, equipmentUpkeepTask.getId());
        if (tpmUpkeepTaskEntity == null) {
            throw new MBootException("未找到对应数据");
        }
        EquipmentUpkeepTask tpmUpkeepTask = new EquipmentUpkeepTask();
        BeanUtils.copyProperties(tpmUpkeepTaskEntity, tpmUpkeepTask);
        tpmUpkeepTask.setEqpStatus(equipmentUpkeepTask.getEqpStatus());

        if (!EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode().equals(tpmUpkeepTaskEntity.getOrderStatus())
                && !EquipmentEnums.UpkeepStatus.EXECUT.getCode().equals(tpmUpkeepTaskEntity.getOrderStatus())) {
            throw new MBootException("工单状态不正确，不允许执行");
        }
        if (EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode().equals(tpmUpkeepTaskEntity.getOrderStatus())) {
            tpmUpkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());
            tpmUpkeepTask.setActualStartTime(new Date());
        }

        for (EquipmentUpkeepTaskDetail tpmUpkeepTaskDetail : equipmentUpkeepTask.getUpkeepTaskDetails()) {
            if (tpmUpkeepTaskDetail.getIsRecord() == 0) {
                tpmUpkeepTaskDetail.setActualVaule("无需记录");
            }
            upkeepTaskDetailService.update(tpmUpkeepTaskDetail);
        }

        // 查询是否有未记录的明细
        Long count = JpaUtil.linq(EquipmentUpkeepTaskDetail.class)
                .equal("taskId", tpmUpkeepTask.getId())
                .equal("isRecord", 1)
                .isNull("actualVaule")
                .count();

        if (count < 1) {
            Date date = new Date();
            tpmUpkeepTask.setActualEndTime(date);
            //判断是否逾期
            if (date.getTime() > tpmUpkeepTaskEntity.getPlanEndTime().getTime()) {
                tpmUpkeepTask.setOverFlag(1);
            }
            tpmUpkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.END.getCode());

            // 计算维修工时
            List<EquipmentUpkeepTaskOperation> tpmUpkeepTaskOperations = JpaUtil.linq(EquipmentUpkeepTaskOperation.class).equal("taskId", tpmUpkeepTaskEntity.getId()).list();
            if (!CollectionUtils.isEmpty(tpmUpkeepTaskOperations)) {
                Date beginStop = new Date();
                long totalWorkTime = DateUtil.between(tpmUpkeepTaskEntity.getActualStartTime(), date, DateUnit.MINUTE);
                long totalStopTime = 0;
                // 循环计算暂停时长
                for (int i = 0; i < tpmUpkeepTaskOperations.size(); i++) {
                    if ("维修暂停".equals(tpmUpkeepTaskOperations.get(i).getOperate())) {
                        beginStop = tpmUpkeepTaskOperations.get(i).getOperateTime();
                    }
                    if ("维修暂停结束".equals(tpmUpkeepTaskOperations.get(i).getOperate())) {
                        totalStopTime += DateUtil.between(beginStop,tpmUpkeepTaskOperations.get(i).getOperateTime(), DateUnit.MINUTE);
                    }
                }
                tpmUpkeepTask.setWorkMinutes(totalWorkTime - totalStopTime);
            }

            insertOperate(tpmUpkeepTask.getId(), "结束保养", "结束保养");
            // 发起签核
        }
        this.update(tpmUpkeepTask);
    }

    @Override
    @Transactional
    public void startExcut(String id) throws MBootException {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class, id);
        if (upkeepTask == null) {
            return;
        }
        // 判断工单状态
        if (!EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode().equals(upkeepTask.getOrderStatus())) {
            throw new MBootException("工单非待开始状态");
        }
        upkeepTask.setActualStartTime(new Date());
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.EXECUT.getCode());
        this.update(upkeepTask);
        insertOperate(upkeepTask.getId(), "开始保养", "开始执行");
    }

    @Override
    @Transactional
    public void stopUpkeepById(String reason, String id) {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class, id);
        if (upkeepTask == null || !EquipmentEnums.UpkeepStatus.EXECUT.getCode().equals(upkeepTask.getOrderStatus())) {
            new MBootException("实体未找到或未开始维修状态！");
        }
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.STOP.getCode());
        this.update(upkeepTask);

        //设置操作记录
        insertOperate(id, "保养暂停", reason);
    }

    @Override
    @Transactional
    public void endStop(String id) {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class, id);
        if (upkeepTask == null || !EquipmentEnums.UpkeepStatus.STOP.getCode().equals(upkeepTask.getOrderStatus())) {
            new MBootException("实体未找到或非暂停状态！");
        }
        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.EXECUT.getCode());
        this.update(upkeepTask);

        //设置操作记录
        insertOperate(id, "保养暂停结束", "保养暂停结束");
    }

    @Override
    @Transactional
    public void reSend(String id, String executor, String reason) throws MBootException {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class, id);
        if (upkeepTask == null) {
            return;
        }
        // 判断工单状态
        if (upkeepTask.getOrderStatus() < Integer.valueOf(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode())
                || EquipmentEnums.UpkeepStatus.END.getCode().equals(upkeepTask.getOrderStatus())) {
            return;
        }

        EquipmentUpkeepTaskTransfer tpmUpkeepTaskTransfer = new EquipmentUpkeepTaskTransfer();
        tpmUpkeepTaskTransfer.setTaskId(id);
        tpmUpkeepTaskTransfer.setOldExecutor(upkeepTask.getExecutor());
        tpmUpkeepTaskTransfer.setNewExecutor(executor);
        tpmUpkeepTaskTransfer.setReason(reason);
        upkeepTaskTransferService.save(tpmUpkeepTaskTransfer);

        upkeepTask.setExecutor(executor);
        this.update(upkeepTask);
    }

    @Override
    @Transactional
    public void signOffBack(String id, String reason) {
        EquipmentUpkeepTask upkeepTask = this.getById(EquipmentUpkeepTask.class, id);
        if (upkeepTask == null) {
            throw new MBootException("id或者实体不存在！");
        }
        // 判断工单状态
        if ( !EquipmentEnums.UpkeepStatus.END.getCode().equals(upkeepTask.getOrderStatus())) {
            throw new MBootException("保养工单状态非结束状态！");
        }

        upkeepTask.setOrderStatus(EquipmentEnums.UpkeepStatus.WAIT_EXECUT.getCode());
        this.update(upkeepTask);
    }

    /**
     * 添加操作记录
     *
     * @param repairId 任务ID
     * @param operate  操作
     * @param reason   原因（主要用具回退填写原因）
     */
    private void insertOperate(String repairId, String operate, String reason) {
        insertOperate(repairId, operate, reason, 0);
    }


    /**
     * 添加操作记录
     *
     * @param repairId 任务ID
     * @param operate  操作
     * @param reason   原因（主要用具回退填写原因）
     */
    private void insertOperate(String repairId, String operate, String reason, long time) {
        EquipmentUpkeepTaskOperation operation = new EquipmentUpkeepTaskOperation();
        //设置任务ID
        operation.setTaskId(repairId);
        //设置操作名称
        operation.setOperate(operate);
        //设置操作原因
        operation.setReason(reason);
        //设置操作时间
        if (time > 0 ){
            operation.setOperateTime(new Date(time));
        }
        //获取当前登录用户
        User loginUser = SecurityUtils.getLoginUser();
        //设置操作人
        operation.setOperator(loginUser.getNickname() + "/" + loginUser.getUsername());
        //保存
        upkeepTaskOperationService.save(operation);
    }

    private String getDepartmentDirector(String departmentId, String dispatchMode) throws MBootException {
        List<User> users = JpaUtil
                .linq(User.class)
                .exists(UserDept.class)
                .equalProperty("userId", "username")
                .equal("deptId", departmentId)
                .end()
                .list();
        if (CollectionUtils.isEmpty(users) && ASSIGN_MODE.equals(dispatchMode)) {
            throw new MBootException("派工模式下该下达目标无负责人");
        } else {
            return users.get(0).getUsername();
        }
    }

    private List<Dept> queryUserDeparts(String username){
        return JpaUtil.linq(Dept.class)
                .exists(UserDept.class)
                .equalProperty("deptId","id")
                .equal("userId",username)
                .list();
    }
}
